/**
 * gislin
 * 2016年4月13日
 */
package io.chance.receiverlei.channel;

import io.chance.receiverlei.datapacket.ModbusCRCUnit;
import io.chance.receiverlei.db.DbHelper;
import io.chance.receiverlei.db.StationStatus;
import io.chance.receiverlei.db.model.BdMoRtSingle;
import io.chance.receiverlei.db.redis.StationService;
import io.chance.receiverlei.main.AppStart;
import lrq.common.ByteUnit;
import lrq.common.MyLog;
import lrq.common.PropertiesUnit;
import org.apache.log4j.Logger;
import org.jboss.netty.buffer.BigEndianHeapChannelBuffer;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.HashMap;

public class MsgReceiverHandler extends SimpleChannelUpstreamHandler {
    private static Logger log;
    private static Logger msgLog;
    HashMap<String, String> pollToTrans01 = PropertiesUnit.getMap("pollToTrans01");
    public static HashMap<String, String> isNewMn = new HashMap<>();

    @Override
    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
        if (log == null) {
            log = MyLog.getLogger(AppStart.logName);
        }

        try {
            BigEndianHeapChannelBuffer r = (BigEndianHeapChannelBuffer) e.getMessage();
            byte[] dataByte = new byte[r.readableBytes()];
            r.readBytes(dataByte);
            if (!ModbusCRCUnit.CRCCheck(dataByte)) {
                log.info("crc验证不通过,报文:" + getMsgString(dataByte));
                return;
            }

            String mn = ChannelManager.getMN(ChannelManager.getChannelId(ctx.getChannel()));
            if (mn == null || "".equals(mn) || "null".equals(mn)) {
                if (dataByte[1] == -1) {//多协议版本功能码FF
                    int multiMn = twoByteArrayToInt(dataByte, 3);
                    ChannelManager.addDevice(multiMn + "", ctx.getChannel());//注册设备
                    mn = multiMn + "";
                    if (multiMn >= 256) {
                        isNewMn.put(mn, "1");
                    }
                }
                if (mn == null || "".equals(mn) || "null".equals(mn)) {
                    log.error("没有对应Socket的合法心跳" + ((InetSocketAddress) ctx.getChannel().getRemoteAddress()).getHostString());
                    return;
                }
            }
            if (dataByte[1] == -1) {
                log.info(mn + "站点心跳2:" + MessageDecode.bytes2Hex(dataByte));
                return;
            }
            msgLog = MyLog.getLogger("msg_" + mn);
            msgLog.info(getMsgString(dataByte));
            StationService.getInstance().updateStationDataReceiveTime(mn);
            BdMoRtSingle single = new BdMoRtSingle().setSITE_ID(mn);
            byte[] data = {0, 0, 0, 0};
            if (isNewMn.containsKey(mn)) {//新协议多指令
                //01 03 16 00 01 00 01 00 01 00 00 00 00 00 0A 00 1E 00 FF 01 04 02 8A 00 00 A3 EA
                //开关量
                single.setPARAMETER(pollToTrans01.get("4"));
                single.setVALUE(String.valueOf(dataByte[4] + dataByte[6] * 4 + dataByte[8] * 2));
                DbHelper.createOrUpdateSingle(single);
                //雷击次数
                single.setPARAMETER(pollToTrans01.get("1"));
                int start = 9;
                data[0] = dataByte[start + 1];
                data[1] = dataByte[start];
//                    System.arraycopy(dataByte, start, data, 0, 2);
                start = start + 2;
                single.setVALUE(String.valueOf(MessageDecode.bytes2Int(data) / 10));
                DbHelper.createOrUpdateSingle(single);
                //电流
                single.setPARAMETER(pollToTrans01.get("3.1"));
                data[0] = dataByte[start + 1];
                data[1] = dataByte[start];
//                    System.arraycopy(dataByte, start, data, 0, 2);
                start = start + 2;
                single.setVALUE(String.valueOf(MessageDecode.bytes2Int(data) / 10.0));
                DbHelper.createOrUpdateSingle(single);
                single.setPARAMETER(pollToTrans01.get("3.2"));
                data[0] = dataByte[start + 1];
                data[1] = dataByte[start];
//                    System.arraycopy(dataByte, start, data, 0, 2);
                start = start + 2;
                single.setVALUE(String.valueOf(MessageDecode.bytes2Int(data) / 10.0));
                DbHelper.createOrUpdateSingle(single);
                single.setPARAMETER(pollToTrans01.get("3.3"));
                data[0] = dataByte[start + 1];
                data[1] = dataByte[start];
//                    System.arraycopy(dataByte, start, data, 0, 2);
                start = start + 2;
                single.setVALUE(String.valueOf(MessageDecode.bytes2Int(data) / 10.0));
                DbHelper.createOrUpdateSingle(single);
                //spd温度
                single.setPARAMETER(pollToTrans01.get("5"));
                data[0] = dataByte[start + 1];
                data[1] = dataByte[start];
//                    System.arraycopy(dataByte, start, data, 0, 2);
                start = start + 2;
                single.setVALUE(String.valueOf(MessageDecode.bytes2Int(data) / 10.0));
                DbHelper.createOrUpdateSingle(single);
                //环境温度
                single.setPARAMETER(pollToTrans01.get("6.1"));
                data[0] = dataByte[start + 1];
                data[1] = dataByte[start];
//                    System.arraycopy(dataByte, start, data, 0, 2);
                start = start + 2;
                single.setVALUE(String.valueOf(MessageDecode.bytes2Int(data) / 10.0));
                DbHelper.createOrUpdateSingle(single);
                //环境湿度
                single.setPARAMETER(pollToTrans01.get("6.2"));
                data[0] = dataByte[start + 1];
                data[1] = dataByte[start];
//                    System.arraycopy(dataByte, start, data, 0, 2);
                start = start + 2;
                single.setVALUE(String.valueOf(MessageDecode.bytes2Int(data) / 10.0));
                DbHelper.createOrUpdateSingle(single);
                //电压
                single.setPARAMETER(pollToTrans01.get("2.1"));
                data[0] = dataByte[start + 1];
                data[1] = dataByte[start];
//                    System.arraycopy(dataByte, start, data, 0, 2);
//                    start = start + 2;
                single.setVALUE(String.valueOf(MessageDecode.bytes2Int(data) / 10.0));
                DbHelper.createOrUpdateSingle(single);
            }
            else {
                int modFuncRet = ByteUnit.ConvertByteToInt8(dataByte[1]);
                int readFuncRet = ByteUnit.ConvertByteToInt8(dataByte[3]);

                if (modFuncRet == 14) {//报警e,长度可能是0,32或8的倍数
                    int dataLen = ByteUnit.ConvertByteToInt8(dataByte[2]);
                    if (dataLen == 0) {
                        log.info(mn + "报警0e反馈长度为0");
                        return;
                    }
                    single.setPARAMETER(pollToTrans01.get("14"));
                    StringBuffer sb = new StringBuffer();
                    for (int i = 0; i < dataLen / 8; i++) {
                        try {
                            data[0] = dataByte[3 + i * 8];
                            int code = MessageDecode.bytes2Int(data);
                            data[0] = dataByte[4 + i * 8];
                            int pos = MessageDecode.bytes2Int(data);
                            String date = getByteDate(Arrays.copyOfRange(dataByte, 5 + i * 8, 9 + i * 8));
                            data[0] = dataByte[9 + i * 8];
                            data[1] = dataByte[10 + i * 8];
                            int value = MessageDecode.bytes2Int(data);
                            if (code < 10) {
                                sb.append(code).append(",").append(pos).append(",").append(date).append(",").append(value).append(";");
                            }
                            else {
                                log.info(mn + "报警类型错误,code:" + code + ",pos:" + pos + ",date:" + date + ",value:" + value);
                            }
                        }
                        catch (Exception e1) {
                            log.error(null, e1);
                        }
                    }
                    single.setVALUE(sb.toString());
                    DbHelper.createOrUpdateSingle(single);
                }
                else if (readFuncRet == 1) {//雷击数量
                    single.setPARAMETER(pollToTrans01.get("1"));
                    System.arraycopy(dataByte, 4, data, 0, 4);
//                    byte[] data = {dataByte[4], dataByte[5], dataByte[6], dataByte[7]};
                    single.setVALUE(String.valueOf(MessageDecode.bytes2Int(data)));
                    DbHelper.createOrUpdateSingle(single);
                }
                else if (readFuncRet == 2) {//电压
                    single.setPARAMETER(pollToTrans01.get("2.1"));
                    data[0] = dataByte[4];
                    data[1] = dataByte[5];
                    single.setVALUE(String.valueOf(MessageDecode.bytes2Int(data)));
                    DbHelper.createOrUpdateSingle(single);
                    single.setPARAMETER(pollToTrans01.get("2.2"));
                    data[0] = dataByte[6];
                    data[1] = dataByte[7];
                    single.setVALUE(String.valueOf(MessageDecode.bytes2Int(data)));
                    DbHelper.createOrUpdateSingle(single);
                    single.setPARAMETER(pollToTrans01.get("2.3"));
                    data[0] = dataByte[8];
                    data[1] = dataByte[9];
                    single.setVALUE(String.valueOf(MessageDecode.bytes2Int(data)));
                    DbHelper.createOrUpdateSingle(single);
                }
                else if (readFuncRet == 3) {//电流
                    single.setPARAMETER(pollToTrans01.get("3.1"));
                    data[0] = dataByte[4];
                    data[1] = dataByte[5];
                    single.setVALUE(String.valueOf(MessageDecode.bytes2Int(data)));
                    DbHelper.createOrUpdateSingle(single);
                    single.setPARAMETER(pollToTrans01.get("3.2"));
                    data[0] = dataByte[6];
                    data[1] = dataByte[7];
                    single.setVALUE(String.valueOf(MessageDecode.bytes2Int(data)));
                    DbHelper.createOrUpdateSingle(single);
                    single.setPARAMETER(pollToTrans01.get("3.3"));
                    data[0] = dataByte[8];
                    data[1] = dataByte[9];
                    single.setVALUE(String.valueOf(MessageDecode.bytes2Int(data)));
                    DbHelper.createOrUpdateSingle(single);
                }
                else if (readFuncRet == 4) {//开关量
                    single.setPARAMETER(pollToTrans01.get("4"));
//                    single.setVALUE(Integer.toBinaryString(dataByte[4]));
                    single.setVALUE(String.valueOf(dataByte[4]));
                    DbHelper.createOrUpdateSingle(single);
                }
                else if (readFuncRet == 5) {//spd温度
                    single.setPARAMETER(pollToTrans01.get("5"));
                    data[0] = dataByte[5];
                    data[1] = dataByte[6];
                    single.setVALUE(String.valueOf(MessageDecode.bytes2Int(data) / 100.0));
                    DbHelper.createOrUpdateSingle(single);
                }
                else if (readFuncRet == 6) {//环境温湿度
                    single.setPARAMETER(pollToTrans01.get("6.1"));
                    data[0] = dataByte[4];
                    data[1] = dataByte[5];
                    single.setVALUE(String.valueOf(MessageDecode.bytes2Int(data) / 100.0));
                    DbHelper.createOrUpdateSingle(single);
                    single.setPARAMETER(pollToTrans01.get("6.2"));
                    data[0] = dataByte[6];
                    data[1] = dataByte[7];
                    single.setVALUE(String.valueOf(MessageDecode.bytes2Int(data) / 100.0));
                    DbHelper.createOrUpdateSingle(single);
                }
                else if (readFuncRet == 7) {//报警数量
                    single.setPARAMETER(pollToTrans01.get("7"));
                    System.arraycopy(dataByte, 4, data, 0, 4);
                    single.setVALUE(String.valueOf(MessageDecode.bytes2Int(data)));
                    DbHelper.createOrUpdateSingle(single);
                }
                else if (readFuncRet == 8) {//报警
                    single.setPARAMETER(pollToTrans01.get("8"));
                    StringBuffer sb = new StringBuffer();
                    for (int i = 0; i < 4; i++) {
                        try {
                            data[0] = dataByte[7 + i * 8];
                            int code = MessageDecode.bytes2Int(data);
                            data[0] = dataByte[8 + i * 8];
                            int pos = MessageDecode.bytes2Int(data);
                            String date = getByteDate(Arrays.copyOfRange(dataByte, 9 + i * 8, 13 + i * 8));
                            data[0] = dataByte[13 + i * 8];
                            data[1] = dataByte[14 + i * 8];
                            int value = MessageDecode.bytes2Int(data);
                            sb.append(code).append(",").append(pos).append(",").append(date).append(",").append(value).append(";");
                        }
                        catch (Exception e1) {
                            log.error(null, e1);
                        }
                    }
                    single.setVALUE(sb.toString());
                    DbHelper.createOrUpdateSingle(single);
                }
                else {
                    log.info("未识别指令：" + MessageDecode.bytes2Hex(dataByte));
                }
            }
//            }
            StationService.getInstance().setStationStatus(StationStatus.workWell, mn);
        }
        catch (Exception e2) {
            log.error("接收数据包出错", e2);
        }
    }

    private static final DateTimeFormatter DTF = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");

    private String getByteDate(byte[] bytes) {
        try {
            String timeStr = MessageDecode.bytes2Hex(bytes);
            int year = (Integer.parseInt(timeStr.substring(0 * 2, 1 * 2), 16) & 0xfc) >> 2;
            int month = (Integer.parseInt(timeStr.substring(0 * 2, 1 * 2), 16) & 0x03) << 2 |
                (Integer.parseInt(timeStr.substring(1 * 2, 2 * 2), 16) & 0xc0) << 6;
            int day = (Integer.parseInt(timeStr.substring(1 * 2, 2 * 2), 16) & 0x3e) >> 1;
            int hour = (Integer.parseInt(timeStr.substring(1 * 2, 2 * 2), 16) & 0x01) << 4 |
                (Integer.parseInt(timeStr.substring(2 * 2, 3 * 2), 16) & 0xF0) >> 4;
            int min = (Integer.parseInt(timeStr.substring(2 * 2, 3 * 2), 16) & 0x0F) << 2 |
                (Integer.parseInt(timeStr.substring(3 * 2, 4 * 2), 16) & 0xF0) >> 6;
            int sec = (Integer.parseInt(timeStr.substring(3 * 2, 4 * 2), 16) & 0x3F);
            return LocalDateTime.of(2000 + year, month, day, hour, min, sec).format(DTF);
        }
        catch (Exception e) {
            log.error("getByteDate", e);
        }
        return null;
    }

    private String getMsgString(byte[] data) {
        return MessageDecode.bytes2Hex(data);
    }

    //根据modbus协议获得32位浮点数，读4字节
    public static Double getDouble32ByModbus(String hexstr) {
        // 先将16进制数转成二进制数0 10000001 00000000000000000000000
        String binarystr = hexString2binaryString(hexstr);
        // 1位符号位(SIGN)=0 表示正数
        String sign = binarystr.substring(0, 1);
        // 8位指数位(EXPONENT)=10000001=129[10进制]
        String exponent = binarystr.substring(1, 9);
        int expint = Integer.parseInt(exponent, 2);
        // 23位尾数位(MANTISSA)=00000000000000000000000
        String last = binarystr.substring(9);
        // 小数点移动位数
        int mobit = expint - 127;
        // 小数点右移18位后得10101001 01101001 110.00000
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < 23; i++) {
            if (i == mobit) {
                sb.append(".");
            }
            char b = last.charAt(i);
            sb.append(b);
        }
        String valstr = "1" + sb.toString();
        Double dval = 0d;
        for (int i = 0; i < valstr.length(); i++) {
            if (valstr.charAt(i) == '.') {
                continue;
            }
            Double d = Math.pow(2, mobit);
            int f = Integer.valueOf(valstr.charAt(i) + "");
            d = d * f;
            mobit = mobit - 1;
            dval = dval + d;
        }
        if (sign.equals("1")) {
            dval = 0 - dval;
        }
        return dval;

    }

    public static String hexString2binaryString(String hexString) {
        if (hexString == null || hexString.length() % 2 != 0) {
            return null;
        }
        String bString = "", tmp;
        for (int i = 0; i < hexString.length(); i++) {
            tmp = "0000" + Integer.toBinaryString(Integer.parseInt(hexString.substring(i, i + 1), 16));
            bString += tmp.substring(tmp.length() - 4);
        }
        return bString;
    }

    public static String formatNum(String hexStr) {
        if (hexStr.length() == 1) {
            hexStr = "0" + hexStr;
        }
        return hexStr;
    }

    public static int bytes2Int(byte[] bytes, int to, int len) {//正常情况len不大于4
        try {
            byte[] newBytes = new byte[4];
            System.arraycopy(bytes, to, newBytes, 0, len);
            return ByteBuffer.wrap(newBytes).order(ByteOrder.LITTLE_ENDIAN).getInt();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    public static int twoByteArrayToInt(byte[] bytes, int start) {
        int value = (bytes[start] << 8) + bytes[start + 1];
        return value;
    }
}
